#include <stdio.h>
#include <sys/inotify.h>
#include <limits.h>
#include <string.h>
#include <sqlite3.h>
#include "openssl/md5.h"
#include <sys/types.h>
#include <fcntl.h>
#include <dirent.h>
#define BUF_LEN (10 * (sizeof(struct inotify_event) + NAME_MAX + 1))
char path[100][100];
int montior_count=0;
int inotifyFd;
sqlite3 * db = 0;//数据库定义 
char * pErrMsg = 0;// 数据库错误信息 
int ret;
static void displayInotifyEvent(struct inotify_event *i)         /* Display information from inotify_ event structure */
{
	//printf("wd =%2d; ", i->wd);
	//if (i->cookie > 0)printf("cookie =%4d; ", i->cookie);
	//printf("mask = ");
	//if (i->mask & IN_ACCESS)printf("IN_ACCESS");
	if (i->mask & IN_ATTRIB)printf("IN_ATTRIB");
	//if (i->mask & IN_CLOSE_NOWRITE) printf("IN_CLOSE_NOWRITE");
	if (i->mask & IN_CLOSE_WRITE) printf("IN_CLOSE_WRITE");
	if (i->mask & IN_CREATE)printf("IN_CREATE");
	if (i->mask & IN_DELETE)printf("IN_DELETE");
	if (i->mask & IN_DELETE_SELF) printf("IN_DELETE_SELF");
	if (i->mask & IN_IGNORED)printf("IN_IGNORED");
	if (i->mask & IN_ISDIR)printf("IN_ISDIR");
	if (i->mask & IN_MODIFY)printf("IN_MODIFY");
	if (i->mask & IN_MOVE_SELF)printf("IN_MOVE_SELF");
	if (i->mask & IN_MOVED_FROM)printf("IN_MOVED_FROM");
	if (i->mask & IN_MOVED_TO)printf("IN_ MOVED_T0");
	//if (i->mask & IN_OPEN)printf("IN_OPEN");
	if (i->mask & IN_Q_OVERFLOW)printf("IN_Q_OVERFLOW");
	if (i->mask & IN_UNMOUNT)printf("IN_UNMOUNT");
	//printf("\n");
	if (i->len > 0)printf("name = %s\n", i->name);
	//printf("cookie = %d\n", i->cookie);
}
int select_callback(void * data, int col_count, char ** col_values, char ** col_Name)// 每条记录回调一次该函数,有多少条就回调多少次
{
	int i;
	for( i=0; i < col_count; i++){
		//printf( "%s = %s\n", col_Name[i], col_values[i] == 0 ? "NULL" : col_values[i] );
		sprintf(path[montior_count],"%s", col_values[i] ); 
	}
	montior_count++;
 	return 0;
}
int Compute_file_md5(const char *file_path, char *md5_str)//计算文件MD5 
{
	int i;
	int fd;
	int ret;
	unsigned char data[1024];
	unsigned char md5_value[16];
	MD5_CTX md5;
 
	fd = open(file_path, O_RDONLY);
	if (-1 == fd)
	{
		perror("open");
		return -1;
	}
	// init md5
	MD5_Init(&md5);
	while (1)
	{
		ret = read(fd, data, 1024);
		if (-1 == ret)
		{
			perror("read");
			return -1;
		}
		MD5_Update(&md5, data, ret);
		if (0 == ret || ret < 1024)break;
	}
	close(fd);
	MD5_Final( md5_value,&md5);
 
	for(i = 0; i < 16; i++)
	{
		snprintf(md5_str + i*2, 2+1, "%02x", md5_value[i]);
	}
	md5_str[32] = '\0'; // add end
	return 0;
}
int getFileSize(char * file)  //计算文件大小 
{
    int size = -1;
    FILE * path;
    path = fopen(file, "rb");
    //path = fopen(file, "r");
    if (NULL == path)
    {
        printf("文件打开失败！\n");
        return  size; //文件大小不可能为负数
    }
    else
    {
        fseek(path, 0, SEEK_END);//设置流文件指针的位置,以SEEK_END为起点，偏移量是0,亦即SEEK_END
        size = ftell(path);//函数结果：当前文件流指针位置相对于文件起始位置的字节偏移量
        fclose(path);
        path = NULL;
    }
    return size;
}
int readFileList(char *basePath)
{
    DIR *dir;
    struct dirent *ptr;
    char base[1000];
	char path_bup[100];
	char md5_str[33];
	char md5_strb[33];
	int i;
	char sql0[100];
    if ((dir=opendir(basePath)) == NULL)perror("Open dir error...");
    while ((ptr=readdir(dir)) != NULL)
    {
        if(strcmp(ptr->d_name,".")==0 || strcmp(ptr->d_name,"..")==0)    ///current dir OR parrent dir
            continue;
        else if(ptr->d_type == 8)    ///file
		{	sprintf(path_bup,"%s/%s", basePath,ptr->d_name);
			for(i=0;i<montior_count;i++)
				if(getFileSize(path_bup)==getFileSize(path[i])){
					Compute_file_md5(path_bup, md5_str);
					Compute_file_md5(path[i], md5_strb);
					if(strcmp(md5_str,md5_strb)==0){
						inotify_add_watch(inotifyFd,path_bup ,IN_ALL_EVENTS);	
					}
            		if(strcmp(path_bup,path[i])!=0){
						sprintf(sql0,"insert into montiorfile select \"%s\",deletetime from montiorfile where path=\"%s\"",path_bup,path[i]);
						int ress=sqlite3_exec( db, sql0, 0, 0, &pErrMsg);
						if(ress!=SQLITE_OK)break;
					}
				}
		}
        else if(ptr->d_type == 10)    ///link file
		{sprintf(path_bup,"%s/%s", basePath,ptr->d_name);
            Compute_file_md5(path_bup, md5_str);
            printf("d_name:%s/%s size:%d MD5=%s\n",basePath,ptr->d_name,getFileSize(path_bup),md5_str);}
        else if(ptr->d_type == 4)    ///dir
        {
            memset(base,'\0',sizeof(base));
            strcpy(base,basePath);
            strcat(base,"/");
            strcat(base,ptr->d_name);
            readFileList(base);
        }
    }
    closedir(dir);
    return 1;
}
void main()
{
	//int inotifyFd;
	int i;
	char *p; 
	char buf[BUF_LEN];
	ssize_t numRead;
	int wd=0;
	char path0[100];
	struct inotify_event *event;
	char sqla[300];
	//sqlite3 * db = 0;//数据库定义 
	//char * pErrMsg = 0;// 数据库错误信息 
	inotifyFd=inotify_init();//inotify实例初始化

	DIR *dir;
    char basePath[1000];//文件
	 
	// 连接数据库
	int ret = sqlite3_open("./leeg.db", &db);
	if( ret != SQLITE_OK )fprintf(stderr, "无法打开数据库: %s", sqlite3_errmsg(db));
	else printf("数据库连接成功!\n");
	
	while(1){
		sleep(1);
		//执行数据库查询，即查询监控的要删除的文件路径 
		montior_count=0;
		sqlite3_exec( db, "select path from montiorfile;", select_callback, 0, &pErrMsg);
		// 追加新的监控项 
		for(i=0;i<montior_count;i++)
		{
			wd=inotify_add_watch(inotifyFd,path[i] ,IN_ALL_EVENTS);
			//printf("%d wd\n",wd);
			if(wd==-1){
				sprintf(sqla,"delete from montiorfile where path=\"%s\"",path[i]);
				sqlite3_exec( db, sqla, 0, 0, &pErrMsg);
			}
		}
		readFileList("/home/lg/z");
		numRead = read(inotifyFd, buf, BUF_LEN);
		for(p=buf;p<buf+numRead;){
			event = (struct inotify_event *) p;
			displayInotifyEvent(event);
			p += sizeof(struct inotify_event) + event->len;
		}
	}
}
